package main

import (
    "fmt"
    "net"
    "flag"
    "io"
    "os"
)

type Client struct{
    ServerIp string
    ServerPort int
    Name string
    conn net.Conn
    flag int
}

func NewClient(serverIp string, serverPort int) *Client {
    //创建客户端对象
    client := &Client{
        ServerIp:serverIp,
        ServerPort:serverPort,
        flag:999,
    }

    //链接server
    conn,err := net.Dial("tcp",fmt.Sprintf("%s:%d",serverIp,serverPort))
    if err != nil {
        fmt.Println("net.Dial err:",err)
        return nil
    }

    client.conn = conn

    return client
}

func (this *Client) menu() bool {
    var flag int

    fmt.Println("1.公聊模式")
    fmt.Println("2.私聊模式")
    fmt.Println("3.更新用户名")
    fmt.Println("0.退出")

    fmt.Scanln(&flag)

    if flag >= 0 && flag <=3 {
        this.flag = flag
        return true
    }else{
        fmt.Println("====请输入合法数字====")
        return false
    }
}

//更新用户名
func (this *Client) UpdateName() bool {
    fmt.Println("====请输入用户名====")
    fmt.Scanln(&this.Name)

    sendMsg := "rename|" + this.Name + "\n"
    _, err := this.conn.Write([]byte(sendMsg))
    if err != nil {
        fmt.Println("conn.Write err:",err)
        return false
    }

    return true
}

//公聊模式
func (this *Client) PublicChan(){
    var chanMsg string
    fmt.Println("请输入消息内容，exit 退出")
    fmt.Scanln(&chanMsg)

    for chanMsg != "exit" {

        if len(chanMsg) != 0 {
            sendMsg := chanMsg + "\n"
            _, err := this.conn.Write([]byte(sendMsg))
            if err != nil {
                fmt.Println("PucblicChan err:",err)
                break
            }
        }

        chanMsg = ""
        fmt.Println("请输入消息内容，exit 退出")
        fmt.Scanln(&chanMsg)
    }
}

//查询在线用户
func (this *Client) SelectUsers(){
    sendMsg := "who\n"
    _, err := this.conn.Write([]byte(sendMsg))
    if err != nil {
        fmt.Println("SelectUsers err:",err)
        return
    }
}

//私聊模式
func (this *Client) PrivateChat(){
    var remoteName string
    var chatMsg string
    this.SelectUsers()
    fmt.Println("请输入聊天对象[用户名], exit退出")
    fmt.Scanln(&remoteName)

    for remoteName != "exit" {
        fmt.Println("请输入消息内容，exit 退出")
        fmt.Scanln(&chatMsg)

        for chatMsg != "exit" {
            //消息内容不为空则发送
            if len(chatMsg) != 0 {
                sendMsg := "to|" + remoteName + "|" + chatMsg + "\n"
                _, err := this.conn.Write([]byte(sendMsg))
                if err != nil {
                    fmt.Println("PucblicChan err:",err)
                    break
                }
            }

            chatMsg = ""
            fmt.Println("请输入消息内容，exit 退出")
            fmt.Scanln(&chatMsg)
        }

        this.SelectUsers()
        remoteName = ""
        fmt.Println("请输入聊天对象[用户名], exit退出")
        fmt.Scanln(&remoteName)
    }

}

func (this *Client) Run(){
    for this.flag != 0 {
        for this.menu() != true {
        }

        //根据不同模式处理不同业务
        switch this.flag {
            case 1:
                //公聊模式
                this.PublicChan()
                break
            case 2:
                //私聊模式
                this.PrivateChat()
                break
            case 3:
                //更新用户名
                this.UpdateName()
                break
        }
    }
}

//处理server回应的消息，直接显示到标准输出
func (this *Client) DealResponse(){
    //永久阻塞监听,一旦client.conn有数据，就直接copy到stdout标准输出上
    io.Copy(os.Stdout,this.conn)

    /*
    //等价于
    buf := make([]byte,4096)
    for {
        client.conn.Read(buf)
        fmt.Println(buf)
    }
    */
}

var serverIp string
var serverPort int

// ./client -ip 127.0.0.1 -port 8888
func init(){
    flag.StringVar(&serverIp,"ip","127.0.0.1","设置服务器IP地址(默认是127.0.0.1)")
    flag.IntVar(&serverPort,"port",8888,"设置服务器端口(默认是8888)")
}

func main(){
    //命令行解析
    flag.Parse()

    client := NewClient(serverIp,serverPort)
    if client == nil {
        fmt.Println("连接失败...\n")
        return
    }

    //单独开启goroutine处理server回应的消息
    go client.DealResponse()

    fmt.Println("连接成功")

    //启动客户端业务
    client.Run()
}